package com.itcz.web.manager;

import com.aliyun.oss.OSS;
import com.aliyun.oss.model.*;
import com.itcz.web.config.OssClientConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

/**
 * oss 对象存储操作
 *
 * @author <a href="https://github.com/liyupi">奥数定理</a>
 * @from <a href="https://blog.csdn.net/qq_63143493?spm=1000.2115.3001.5343">个人博客</a>
 */
@Component
@Slf4j
public class OssManager {

    @Resource
    private OssClientConfig ossClientConfig;

    @Resource
    private OSS ossClient;

    /**
     * 上传文件（默认覆盖已存在的文件）
     * @param file 文件
     */
    public void putObject(File file) {
        this.putObject(file.getName(), file);
    }

    /**
     * 上传文件（默认覆盖已存在的文件）
     * @param objectName 文件名
     * @param file 文件
     */
    public void putObject(String objectName, File file) {
        this.putObject(objectName, file, true);
    }

    /**
     * 上传文件
     * @param file 文件
     * @param isCover 文件存在时是否覆盖
     */
    public void putObject(File file, boolean isCover) {
        this.putObject(file.getName(), file, isCover);
    }

    /**
     * 上传文件
     * @param objectName 文件名
     * @param file 文件
     * @param isCover 文件存在时是否覆盖
     */
    public void putObject(String objectName, File file, boolean isCover) {
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException ignored) {

        }
        this.putObject(objectName, inputStream, isCover);
    }

    /**
     * 上传文件（默认覆盖已存在的文件）
     * @param objectName 文件名
     * @param inputStream 文件流
     */
    public void putObject(String objectName, InputStream inputStream) {
        this.putObject(objectName, inputStream, true);
    }

    /**
     * 上传文件
     * @param objectName 文件名
     * @param inputStream 文件流
     * @param isCover 文件存在时是否覆盖
     */
    public void putObject(String objectName, InputStream inputStream, boolean isCover) {
        // 判断是否覆盖已存在的文件
        if (!isCover && this.doesObjectExist(objectName)) {
            log.warn("文件[{}]已存在，无需上传", objectName);
            return;
        }
        // 创建PutObjectRequest对象。
        PutObjectRequest putObjectRequest = new PutObjectRequest(ossClientConfig.getBucketName(), objectName, inputStream);
        // 上传文件
        this.ossClient.putObject(putObjectRequest);
    }

    /**
     * 下载文件
     * @param objectName 文件名
     * @return 文件流
     */
    public InputStream getObject(String objectName) {
        // 判断文件是否存在
        if (!this.doesObjectExist(objectName)) {
            throw new IllegalArgumentException(String.format("文件[%s]不存在", objectName));
        }

        // ossObject包含文件所在的存储空间名称、文件名称、文件元数据以及一个输入流。
        OSSObject ossObject = this.ossClient.getObject(ossClientConfig.getBucketName(), objectName);
        return ossObject.getObjectContent();
    }

    /**
     * 下载文件到本地路径(采用多线程下载）
     *
     * @param objectName    文件名
     * @param localFilePath 本地文件路径
     */
    public void getObject(String objectName, String localFilePath) throws Throwable {
        // 判断文件是否存在
        if (!this.doesObjectExist(objectName)) {
            throw new IllegalArgumentException(String.format("文件[%s]不存在", objectName));
        }

        // 指定下载文件地址
        DownloadFileRequest downloadFileRequest = new DownloadFileRequest(ossClientConfig.getBucketName(), objectName);
        // 指定下载文件到本地文件地址
        downloadFileRequest.setDownloadFile(localFilePath);
        // 指定并发线程数量
        downloadFileRequest.setTaskNum(10);
        // 下载文件
        DownloadFileResult downloadRes = ossClient.downloadFile(downloadFileRequest);
        // 下载成功时，会返回文件元数据
        downloadRes.getObjectMetadata();
    }

    /**
     * 检查文件是否存在
     * @param objectName 文件名
     * @return 文件是否存在
     */
    public boolean doesObjectExist(String objectName) {
        // 判断文件是否存在。如果返回值为true，则文件存在，否则存储空间或者文件不存在。
        return this.ossClient.doesObjectExist(ossClientConfig.getBucketName(), objectName);
    }
}
